package edu.uw.cs.cse461.sp12.OS;

import org.json.JSONException;
import org.json.JSONObject;

import edu.uw.cs.cse461.sp12.util.Log;

public class DDNSException extends Exception {
	private static final String TAG = "DDNSException";
	
	public static enum DDNSExceptionType {
		DEFAULT,
		NO_SUCH_NAME,
		NO_ADDRESS,
		AUTHORIZATION,
		RUNTIME,
		TTL_EXPIRED,
		ZONE
	}
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -8335747784369852111L;

	private static int convertToExceptionNum(DDNSExceptionType type) {
		return type.ordinal();
	}
	
	/**
	 * @return The Exception Number of the exception (to put in the JSON transferred over RPC)
	 */
	public int getExceptionNum() {
		return DDNSExceptionType.DEFAULT.ordinal();
	}
	
	public static DDNSException createFromJSON(JSONObject json) throws JSONException {
		Log.d(TAG, "DDNSException: " + json.toString());
		int exceptionNum = json.getInt("exceptionnum");
		String message = json.getString("message");
		
		if (exceptionNum == convertToExceptionNum(DDNSExceptionType.NO_SUCH_NAME)) {
			return new DDNSNoSuchNameException(message);
		} else if (exceptionNum == convertToExceptionNum(DDNSExceptionType.NO_ADDRESS)) {
			return new DDNSNoAddressException(message);
		} else if (exceptionNum == convertToExceptionNum(DDNSExceptionType.AUTHORIZATION)) {
			return new DDNSAuthorizationException(message);
		} else if (exceptionNum == convertToExceptionNum(DDNSExceptionType.RUNTIME)) {
			return new DDNSRuntimeException(message);
		} else if (exceptionNum == convertToExceptionNum(DDNSExceptionType.TTL_EXPIRED)) {
			return new DDNSTTLExpiredException(message);
		} else if (exceptionNum == convertToExceptionNum(DDNSExceptionType.ZONE)) {
			String zone = json.getString("zone");
			return new DDNSZoneException(zone, message);
		} else {
			throw new JSONException("Invalid exception number: " + exceptionNum);
		}
	}
	
	/**
	 * Should not be able to construct DDNSExceptions directly
	 */
	private DDNSException() {
		super();
	}
	
	/**
	 * Should not be able to construct DDNSExceptions directly
	 */
	private DDNSException(String msg) {
		super(msg);
	}

	/**
	 * Should not be able to construct DDNSExceptions directly
	 */
	private DDNSException(String msg, Exception e) {
		super(msg, e);
	}

	public static class DDNSNoAddressException extends DDNSException {
		/**
		 * 
		 */
		private static final long serialVersionUID = 6251210850803762885L;
		
		public DDNSNoAddressException() {
			super();
		}
		
		public DDNSNoAddressException(String msg) {
			super(msg);
		}

		public DDNSNoAddressException(String msg, Exception e) {
			super(msg, e);
		}
		
		@Override
		public int getExceptionNum() {
			return DDNSExceptionType.NO_ADDRESS.ordinal();
		}
	}

	public static class DDNSNoSuchNameException extends DDNSException {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1719126688209106514L;
		
		public DDNSNoSuchNameException() {
			super();
		}
		
		public DDNSNoSuchNameException(String msg) {
			super(msg);
		}

		public DDNSNoSuchNameException(String msg, Exception e) {
			super(msg, e);
		}
		
		@Override
		public int getExceptionNum() {
			return DDNSExceptionType.NO_SUCH_NAME.ordinal();
		}
	}

	public static class DDNSAuthorizationException extends DDNSException {
		/**
		 * 
		 */
		private static final long serialVersionUID = -8982509773698902773L;

		public DDNSAuthorizationException() {
			super();
		}
		
		public DDNSAuthorizationException(String msg) {
			super(msg);
		}

		public DDNSAuthorizationException(String msg, Exception e) {
			super(msg, e);
		}
		
		@Override
		public int getExceptionNum() {
			return DDNSExceptionType.AUTHORIZATION.ordinal();
		}
	}

	public static class DDNSRuntimeException extends DDNSException {
		/**
		 * 
		 */
		private static final long serialVersionUID = 8275229804865115340L;

		public DDNSRuntimeException() {
			super();
		}
		
		public DDNSRuntimeException(String msg) {
			super(msg);
		}

		public DDNSRuntimeException(String msg, Exception e) {
			super(msg, e);
		}
		
		@Override
		public int getExceptionNum() {
			return DDNSExceptionType.RUNTIME.ordinal();
		}
	}

	public static class DDNSTTLExpiredException extends DDNSException {
		/**
		 * 
		 */
		private static final long serialVersionUID = 5842577600560472727L;

		public DDNSTTLExpiredException() {
			super();
		}
		
		public DDNSTTLExpiredException(String msg) {
			super(msg);
		}

		public DDNSTTLExpiredException(String msg, Exception e) {
			super(msg, e);
		}
		
		@Override
		public int getExceptionNum() {
			return DDNSExceptionType.TTL_EXPIRED.ordinal();
		}
	}

	public static class DDNSZoneException extends DDNSException {
		/**
		 * 
		 */
		private static final long serialVersionUID = 4926167557930121717L;
		
		private String zone;

		public DDNSZoneException(String zone) {
			super();
			this.zone = zone;
		}
		
		public DDNSZoneException(String zone, String msg) {
			super(msg);
			this.zone = zone;
		}

		public DDNSZoneException(String zone, String msg, Exception e) {
			super(msg, e);
			this.zone = zone;
		}
		
		public String getZone() {
			return this.zone;
		}
		
		@Override
		public int getExceptionNum() {
			return DDNSExceptionType.ZONE.ordinal();
		}
	}
}
